home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 19 / Mac Magazin and MacEasy Magazine CD - Issue 19.iso / Utilities / CornerClock ƒ / CornerClock.p < prev    next >
Text File  |  1996-02-04  |  9KB  |  388 lines

  1. CornerClock is a pascal program based upon Masafumi Ueda's MBarClock program.
  2.  
  3. MBarClock was a program which displayed the time or date in the menu bar to the left
  4. of the Apple menu.  CornerClock uses that same feature and adds sound.  
  5.  
  6. I converted Masafumi's MBarClock from C to Pascal, and then began forging it into 
  7. a chime replacement program.  Currently, if you have long chimes activated with your
  8. clock which comes with system 7.5, you may experience a very annoying distorted
  9. sound which interrupts your chime.  This is a known bug with the system, as it does not
  10. appear to lock the sound handle when it plays it (it should lock it because it plays it
  11. asynchronously).  CornerClock plays the hourly chime asynchronously, but locks the
  12. handle so you get a smooth play.
  13.  
  14. CornerClock will play a grandfather clock chime on the hour (3 chimes as 3:00, 4 at 4:00, etc.).
  15.  
  16. When you place the cursor over the time, it will change to the date for 2 seconds, then change back
  17. to the time (same feature in MBarClock except now there is sound).  I've also added some menus
  18. to CornerClock so that you can toggle the date and time, and force a chime.
  19.  
  20. There are many enhancements which can be made, like changing the chime sound, changing the
  21. volume, etc., but I'm releasing it as is to provide the Pascal community with some more sample 
  22. Pascal code.  Feel free to send me any questions or notes of thanks.
  23.  
  24.  
  25. CornerClock ©Bill Catambay, 1996,  catambay@aol.com
  26. All rights reserved worldwide.
  27. }
  28. Program CornerClock;
  29.  
  30. Uses 
  31.     Toolbox, Sound, Resources, Icons;
  32.     
  33. Var
  34.     AppleMenu, FileMenu, EditMenu: MenuHandle;
  35.     ClockPort: CGrafPtr;
  36.     NUMs: array[0..10] of CIconHandle;
  37.     running: Boolean;
  38.     ClockRect: array[0..3] of Rect;
  39.     Corner: Rect;
  40.     bkGnd: RgnHandle;
  41.     dispStat: integer;
  42.     chimes: integer;
  43.     chimeStart: longint;
  44.     dateStart: longint;
  45.     gBackground: boolean;
  46.     sounds: array[0..3] of SndListHandle;
  47.     sndChans: array[0..3] of SndChannelPtr;
  48.     backupChan: SndChannelPtr;
  49.     forceChime: boolean;
  50.     
  51. Const
  52.     kDisplayTime = 0;
  53.     kDisplayDate = 1;
  54.     kChime = 2;
  55.     kAbout = 3;
  56.  
  57. Procedure Die;
  58.  
  59.     begin
  60.     SysBeep(1);
  61.     SysBeep(1);
  62.     SysBeep(1);
  63.     ExitToShell;
  64.     end;
  65.  
  66. Procedure CheckMachine;
  67.  
  68. Var
  69.     sysEnv: SysEnvRec;
  70.     i: integer;
  71.     
  72.     begin
  73.     i := SysEnvirons(curSysEnvVers, sysEnv);
  74.     if i <> noErr then
  75.         Die;
  76.     if not sysEnv.hasColorQD then
  77.         Die;
  78.     if sysEnv.systemVersion < $700 then
  79.         Die;
  80.     end;
  81.  
  82. Procedure OpenClockPort;
  83.  
  84.     begin
  85.     ClockPort := CGrafPtr(NewPtrClear(sizeof(CGrafPort)));
  86.     if ClockPort = NIL then
  87.         Die;
  88.     OpenCPort(ClockPort);
  89.     end;
  90.  
  91. Procedure SetupMenu;
  92.  
  93.     begin
  94.     ClearMenuBar;
  95.     AppleMenu := GetMenu(128);
  96.     InsertMenu(AppleMenu,0);
  97.     AppendResMenu(AppleMenu,'DRVR');
  98.     FileMenu := GetMenu(129);
  99.     InsertMenu(FileMenu,0);
  100.     EditMenu := GetMenu(130);
  101.     InsertMenu(EditMenu,0);
  102.     DrawMenuBar;
  103.     end;
  104.  
  105. Procedure LoadIcons;
  106.  
  107. Var
  108.     i: integer;
  109.     
  110.     begin
  111.     for i := 0 to 10 do
  112.         NUMs[i] := GetCIcon(2000 + i);
  113.     end;
  114.  
  115. Procedure SetupRects;
  116.  
  117. Var
  118.     rgn: RgnHandle;
  119.     r: Rect;
  120.     
  121.     begin
  122.     SetRect(ClockRect[0], 2,2,10,10);
  123.     SetRect(ClockRect[1], 8,2,16,10);
  124.     SetRect(ClockRect[2], 2,10,10,18);
  125.     SetRect(ClockRect[3], 8,10,16,18);
  126.     bkGnd := NewRgn;
  127.     SetRect(corner,0,0,16,19);
  128.     RectRgn(bkGnd,corner);
  129.     UnionRect(ClockRect[0], ClockRect[3], r);
  130.     r.bottom := r.bottom - 1;
  131.     r.right := r.right - 2;
  132.     rgn := NewRgn;
  133.     RectRgn(rgn, r);
  134.     DiffRgn(bkGnd, rgn, bkGnd);
  135.     DisposeRgn(rgn);
  136.     end;
  137.  
  138. Procedure InitAppl;
  139.  
  140. Var
  141.     i: integer;
  142.     
  143.     begin
  144.     CheckMachine;
  145.     OpenClockPort;
  146.     SetupMenu;
  147.     LoadIcons;
  148.     SetupRects;
  149.     dispStat := kDisplayTime;
  150.     running := true;
  151.     chimes := 0;
  152.     chimeStart := 0;
  153.     forceChime := False;
  154.     gBackground := false;
  155.     for i := kDisplayTime to kAbout do
  156.         begin
  157.         sounds[i] := SndListHandle(GetResource(soundListRsrc,128 + i));
  158.         HLockHi(Handle(sounds[i]));
  159.         sndChans[i] := NIL;
  160.         end;
  161.     backupChan := NIL;
  162.     end;
  163.  
  164. Procedure DoSound(sndID: integer);
  165.  
  166. Var
  167.     err: OSErr;
  168.     sndCmd: SndCommand;
  169.     sndHead: SoundHeaderPtr;
  170.     SndChanStat: SCStatus;
  171.     
  172.     begin
  173.     if sounds[sndID] = NIL then
  174.         begin
  175.         sysBeep(1);
  176.         exit(DoSound);
  177.         end;
  178.     if (sndChans[sndID] <> NIL) and (backupChan <> NIL) then
  179.         begin
  180.         err := SndDisposeChannel(backupChan, True);
  181.         backupChan := NIL;
  182.         end;
  183.     if sndChans[sndID] <> NIL then
  184.         begin
  185.         backupChan := sndChans[sndID];
  186.         sndChans[sndID] := NIL;
  187.         end;
  188.     err := SndNewChannel(sndChans[sndID], sampledSynth, 0, NIL);
  189.     if (err <> noErr) or (sndChans[sndID] = NIL) then
  190.         begin
  191.         sysBeep(1);
  192.         exit(DoSound);
  193.         end;
  194.     sndHead := SoundHeaderPtr(longint(sounds[sndID]^) + 20);
  195.     sndCmd.cmd := bufferCmd;
  196.     sndCmd.param1 := 0;
  197.     sndCmd.param2 := ORD4(sndHead);
  198.     err := SndDoCommand(sndChans[sndID], sndCmd, false);
  199.     err := SndChannelStatus(sndChans[sndID], sizeof(SndChanStat), @SndChanStat);
  200.     if err <> noErr then
  201.         begin
  202.         sysBeep(1);
  203.         err := SndDisposeChannel(sndChans[sndID], True);
  204.         sndChans[sndID] := NIL;
  205.         exit(DoSound);
  206.         end;
  207. {    
  208.     chimeStart := TickCount;
  209.     While SndChanStat.scChannelBusy and (not Button) and (Err = NoErr) and (SndArray[1] <> NIL) do
  210.         Err := SndChannelStatus(SndArray[1], sizeof(SndChanStat), @SndChanStat);}
  211.     end;
  212.     
  213. Procedure DoAbout;
  214.  
  215. Var
  216.     p: GrafPtr;
  217.     d: DialogPtr;
  218.     
  219.     begin
  220.     GetPort(p);
  221.     d := GetNewDialog(128, NIL, WindowPtr(-1));
  222.     DrawDialog(d);
  223.     DoSound(kAbout);
  224.     repeat until Button;
  225.     DisposeDialog(d);
  226.     SetPort(p);
  227.     FlushEvents(mDownMask, 0);
  228.     end;
  229.  
  230. Procedure SwitchView;
  231.  
  232.     begin
  233.     dispStat := (dispStat + 1) mod 2;
  234.     doSound(dispStat);
  235.     if dispStat = kDisplayDate then
  236.         dateStart := TickCount;
  237.     end;
  238.     
  239. Procedure DoMenu(SelMenu: longint);
  240.  
  241. Var
  242.     item,i: integer;
  243.     s: Str255;
  244.     
  245.     begin
  246.     item := LoWord(SelMenu);
  247.     case HiWord(SelMenu) of
  248.         128:    if item = 1 then
  249.                     DoAbout
  250.                 else
  251.                     begin
  252.                     GetMenuItemText(AppleMenu, item, s);
  253.                     i := OpenDeskAcc(s);
  254.                     end;
  255.         129:    case item of
  256.                 1,2:    SwitchView;
  257.                 3:        forceChime := True;
  258.                 5:        running := false;
  259.                 {CASE}    end;
  260.     {CASE}        end;
  261.     HiliteMenu(0);
  262.     end;
  263.  
  264. Procedure UpdateWindow(wp: WindowPtr);
  265.  
  266.     begin
  267.     SetPort(wp);
  268.     BeginUpdate(wp);
  269.     EndUpdate(wp);
  270.     end;
  271.  
  272. Procedure DrawDigit(upper,lower: integer; upShow10, loShow10: boolean);
  273.  
  274. Var
  275.     p: GrafPtr;
  276.     
  277.     begin
  278.     GetPort(p);
  279.     SetPort(GrafPtr(ClockPort));
  280.     ForeColor(blackColor);
  281.     PaintRgn(bkGnd);
  282.     if (upper >= 10) | upShow10 then
  283.         PlotCIcon(ClockRect[0], NUMs[ (upper div 10) mod 10])
  284.     else
  285.         PlotCIcon(ClockRect[0], NUMs[10]);
  286.     PlotCIcon(ClockRect[1], NUMs[upper mod 10]);
  287.     if (lower >= 10) | loShow10 then
  288.         PlotCIcon(ClockRect[2], NUMs[(lower div 10) mod 10])
  289.     else
  290.         PlotCIcon(ClockRect[2], NUMs[10]);
  291.     PlotCIcon(ClockRect[3], NUMs[lower mod 10]);
  292.     SetPort(p);
  293.     end;
  294.  
  295. Procedure DrawClock;
  296.  
  297. Const    
  298.     chimeOn = 0;
  299.     
  300. Var
  301.     dt: DateTimeRec;
  302.     p: GrafPtr;
  303.     pt: point;
  304.     
  305.     begin
  306.     GetPort(p);
  307.     SetPort(GrafPtr(ClockPort));
  308.     GetTime(dt);
  309.     GetMouse(pt);
  310.     if PtInRect(pt, corner) and (dispStat = kDisplayTime) then
  311.         SwitchView;
  312.     if (dispStat = kDisplayDate) & (dateStart + 300 < TickCount) then
  313.         SwitchView;
  314.     ForeColor(blackColor);
  315.     PaintRgn(bkGnd);
  316.     case dispStat of 
  317.         kDisplayDate:    DrawDigit(dt.month, dt.day, false, false);
  318.         kDisplayTime:    DrawDigit(dt.hour mod 12, dt.minute, false, true);
  319.     {CASE}                end;
  320.     if ((dt.minute = chimeOn) or forceChime) and (chimes = 0) then
  321.         chimes := dt.hour mod 12;
  322.     if (chimes > 0) & ((chimeStart = 0) | (chimeStart + 120 < TickCount)) then
  323.         begin
  324.         doSound(kChime);
  325.         chimeStart := TickCount;
  326.         dec(chimes);
  327.         if chimes = 0 then
  328.             dec(chimes);
  329.         end
  330.     else if (chimes = -1) & (dt.minute <> chimeOn) then
  331.         begin
  332.         chimes := 0;
  333.         forceChime := False;
  334.         chimeStart := 0;
  335.         end;
  336.     SetPort(p);
  337.     end;
  338.  
  339. Procedure MainLoop;
  340.  
  341. Var
  342.     event: EventRecord;
  343.     dw: WindowPtr;
  344.     ascii: char;
  345.     sleep: longint;
  346.     i: integer;
  347.     err: OSErr;
  348.     
  349.     begin
  350.     repeat
  351.         DrawClock;
  352.         if chimes > 0 then
  353.             sleep := 1
  354.         else
  355.             sleep := 20;
  356.         if WaitNextEvent(everyEvent, event, sleep, NIL) then
  357.             case event.what of
  358.                 mouseDown:    case FindWindow(event.where, dw) of
  359.                                 inMenuBar:    DoMenu(MenuSelect(event.where));
  360.                             {CASE}            end;
  361.                 keyDown:    begin
  362.                             ascii := chr(BAnd(event.message,charCodeMask));
  363.                             if BAnd(event.modifiers,cmdKey) > 0 then
  364.                                 DoMenu(MenuKey(ascii));
  365.                             end;
  366.                 updateEvt:    UpdateWindow(WindowPtr(event.message));
  367.                 osEvt:        if BAnd(brotl(event.message,8),$FF) = suspendResumeMessage then
  368.                                 gBackground := BAnd(event.message,resumeFlag) = 0;
  369.             {CASE}            end;
  370.     until not running;
  371.     DisposeRgn(bkGnd);    
  372.     for i := 0 to 2 do
  373.         begin
  374.         HUnLock(Handle(sounds[i]));
  375.         DisposeHandle(Handle(sounds[i]));
  376.         err := SndDisposeChannel(sndChans[i], True);
  377.         end;
  378.     if backupChan <> NIL then
  379.         err := SndDisposeChannel(backupChan, True);
  380.     end;
  381.  
  382. begin
  383. InitToolbox;
  384. FlushEvents(everyEvent, 0);
  385. InitAPPL;
  386. MainLoop;
  387. end.